package cn.tedu.medicalappointmentsystemk.service.impl;

import cn.tedu.medicalappointmentsystemk.dao.persist.repository.AppointmentRepository;
import cn.tedu.medicalappointmentsystemk.dao.persist.repository.PatientRepository;
import cn.tedu.medicalappointmentsystemk.handler.ServiceException;
import cn.tedu.medicalappointmentsystemk.pojo.bo.AppointmentSelectBO;
import cn.tedu.medicalappointmentsystemk.pojo.bo.AppointmentSelectByIdBO;
import cn.tedu.medicalappointmentsystemk.pojo.bo.AppointmentSelectByUserIdBO;
import cn.tedu.medicalappointmentsystemk.pojo.param.AppointmentAddParam;
import cn.tedu.medicalappointmentsystemk.pojo.param.AppointmentUpdateParam;
import cn.tedu.medicalappointmentsystemk.pojo.po.AppointmentPO;
import cn.tedu.medicalappointmentsystemk.pojo.po.PageData;
import cn.tedu.medicalappointmentsystemk.pojo.vo.PatientUpdateVO;
import cn.tedu.medicalappointmentsystemk.response.ServiceCode;
import cn.tedu.medicalappointmentsystemk.service.AppointmentService;
import cn.tedu.medicalappointmentsystemk.util.PageInfoToPageDataConverter;
import com.alibaba.fastjson.JSON;
import com.github.pagehelper.Page;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.data.redis.core.ValueOperations;
import org.springframework.stereotype.Service;

import java.util.List;
import java.util.Random;
import java.util.Set;
import java.util.concurrent.TimeUnit;


@Service
@Slf4j
public class AppointmentServiceImpl implements AppointmentService {
    @Autowired
    private AppointmentRepository appointmentRepository;
    @Autowired
    private PatientRepository patientRepository;
    @Autowired
    private StringRedisTemplate redisTemplate;

    @Value("${medical.dao.default-query-page-size}")
    private int pageSize;

    @Value("${medical.redis.duration-in-seconds}")
    private int Seconds;

    @Override
    public AppointmentSelectByIdBO selectAppointmentById(Long id) {
        AppointmentPO po = appointmentRepository.selectAppointment(id);
        AppointmentSelectByIdBO bo = new AppointmentSelectByIdBO();
        BeanUtils.copyProperties(po,bo);
        bo.setNumber(patientRepository.selectDetailById(po.getPatientId()).getNumber());
        return bo;
    }

    @Override
    public void insert(AppointmentAddParam param) {
        Long doctorId = appointmentRepository.selectAppointmentByCreateDate
                (param.getCreateDate(),param.getPatientId());
        if (doctorId != null){
            String message="你当天已有预约!";
            throw new ServiceException(ServiceCode.ERROR_CONFLICT,message);
        }
        AppointmentPO po = new AppointmentPO();
        BeanUtils.copyProperties(param, po);
        po.setAppointment("Ap" + ("" + System.currentTimeMillis()).substring(4));
        if (patientRepository.selectDetailById(param.getPatientId()).getNumber() == null) {
            PatientUpdateVO vo = new PatientUpdateVO();
            vo.setId(param.getPatientId());
            vo.setNumber("Num" + ("" + System.currentTimeMillis()).substring(5));
            Integer rows = patientRepository.update(vo);
            if (rows != 1) {
                String message = "新增预约失败!";
                log.error(message);
                throw new ServiceException(ServiceCode.ERROR_INSERT, message);
            }
        }
        Integer row = appointmentRepository.insert(po);
        if (row != 1) {
            String message = "新增预约失败!";
            log.error(message);
            throw new ServiceException(ServiceCode.ERROR_INSERT, message);
        }
        deleteRedisTemplate();
    }

    private void deleteRedisTemplate(){
        Set<String> keys = redisTemplate.keys(APPOINTMENT_REDIS_HEADER+"*");

        if (keys != null) {
            for (String key : keys) {
                redisTemplate.delete(key);
            }
        }
    }

    @Override
    public PageData<AppointmentSelectBO> selectAppointment(Integer pageNum) {
        String cacheKey = APPOINTMENT_REDIS_HEADER+"pageNum:"+pageNum;
        ValueOperations<String, String> opsForString = redisTemplate.opsForValue();
        String appointmentJson = opsForString.get(cacheKey);
        if (StringUtils.isEmpty(appointmentJson)) {
            PageHelper.startPage(pageNum, pageSize);
            Page<AppointmentSelectBO> page = appointmentRepository.selectAppointment();
            PageInfo<AppointmentSelectBO> pageInfo = new PageInfo<>(page);
            PageData<AppointmentSelectBO> pageData = PageInfoToPageDataConverter.convert(pageInfo);
            appointmentJson = JSON.toJSONString(pageData);
            opsForString.set(cacheKey,appointmentJson,
                    Seconds +new Random().nextInt(Seconds),TimeUnit.SECONDS);
            return pageData;
        }else {
            return JSON.toJavaObject(JSON.parseObject(appointmentJson),PageData.class);
        }
    }

    @Override
    public void deleteAppointmentById(Long id) {
        Integer row = appointmentRepository.deleteAppointmentById(id);
        if (row != 1){
            String message = "删除预约失败!";
            log.error(message);
            throw new ServiceException(ServiceCode.ERROR_DELETE, message);
        }
        deleteRedisTemplate();
    }

    @Override
    public void updateAppointment(AppointmentUpdateParam param) {
        AppointmentPO po = new AppointmentPO();
        BeanUtils.copyProperties(param,po);
        Integer row = appointmentRepository.updateAppointment(po);
        if (row != 1){
            String message = "修改预约失败!";
            log.error(message);
            throw new ServiceException(ServiceCode.ERROR_UPDATE, message);
        }
        deleteRedisTemplate();
    }

    @Override
    public AppointmentSelectByUserIdBO selectAppointmentByUserId(Long id) {
        return appointmentRepository.selectByUserId(id);
    }

    @Override
    public PageData<AppointmentSelectByUserIdBO> selectAppointmentsByUserId(Long id,Integer pageNum) {
        String cacheKey = APPOINTMENT_REDIS_HEADER+"UserId:" + id + ":pageNum:" + pageNum;
        ValueOperations<String, String> opsForString = redisTemplate.opsForValue();
        String appointmentJson = opsForString.get(cacheKey);
        if (StringUtils.isEmpty(appointmentJson)) {
            PageHelper.startPage(pageNum, pageSize);
            Page<AppointmentSelectByUserIdBO> page = appointmentRepository.selectAppointmentsByUserId(id);
            PageInfo<AppointmentSelectByUserIdBO> pageInfo = new PageInfo<>(page);
            PageData<AppointmentSelectByUserIdBO> pageData = PageInfoToPageDataConverter.convert(pageInfo);
            appointmentJson = JSON.toJSONString(pageData);
            opsForString.set(cacheKey,appointmentJson,
                    Seconds +new Random().nextInt(Seconds),TimeUnit.SECONDS);
            return pageData;
        }else {
            return JSON.toJavaObject(JSON.parseObject(appointmentJson),PageData.class);
        }
    }

    @Override
    public Integer selectTotal() {
        return appointmentRepository.selectTotal();
    }

    @Override
    public Integer selectToday() {
        return appointmentRepository.selectToday();
    }

    @Override
    public PageData<AppointmentSelectBO> searchToday(Integer pageNum) {
        PageHelper.startPage(pageNum,pageSize);
        Page<AppointmentSelectBO> page = appointmentRepository.searchToday();
        PageInfo<AppointmentSelectBO> pageInfo = new PageInfo<>(page);
        return PageInfoToPageDataConverter.convert(pageInfo);
    }

    @Override
    public PageData<AppointmentSelectBO> searchLastWeek(Integer pageNum) {
        PageHelper.startPage(pageNum,pageSize);
        Page<AppointmentSelectBO> page = appointmentRepository.searchLastWeek();
        PageInfo<AppointmentSelectBO> pageInfo = new PageInfo<>(page);
        return PageInfoToPageDataConverter.convert(pageInfo);
    }
    @Override
    public PageData<AppointmentSelectBO> searchLastMonth(Integer pageNum) {
        PageHelper.startPage(pageNum,pageSize);
        Page<AppointmentSelectBO> page = appointmentRepository.searchLastMonth();
        PageInfo<AppointmentSelectBO> pageInfo = new PageInfo<>(page);
        return PageInfoToPageDataConverter.convert(pageInfo);
    }
    @Override
    public Integer selectLastMonth() {
        return appointmentRepository.selectLastMonth();
    }

    @Override
    public List<AppointmentSelectBO> selectByNickname(String nickname) {
        return appointmentRepository.selectByNickname(nickname);
    }
}